#pragma once

#include <string>
#include "util.h"
#include "context.h"
#include "Md5.h"


template<typename T, class=typename std::enable_if<std::is_base_of<google::protobuf::Message, T>::value>::type >
inline void httpServerBack(std::uint32_t request_id, T* msg)
{
    int status_code = 404;
    std::string body;
    if (msg != nullptr)
    {
        if (!CTools::ToJson(body, *msg))
        {
            log_error("req to json failed, req:%s", msg->ShortDebugString().c_str());
        }
        else
        {
            log_debug("req:%s", msg->ShortDebugString().c_str());
            
            status_code = 200;
        }
    }
    std::map<std::string,std::string> heads;
    heads["Content-Type"] = "application/json";
    Ctx.msg_router.httpServerBack(request_id, status_code, heads, body);
}

inline std::string httpGetGameAccKey(const std::string& acc)
{
    // TODO: 临时先放这, 后面从缓存加载
    return "CRN4C5O1GE7PDW8NXU";
}

inline bool httpCheckRequest(const HttpData& data)
{
    std::string acc_key;
    std::string sign_md5;
    do
    {
        if (data.http_session.uid == 0)  break;
        if (data.http_session.acc.empty())  break;
        acc_key = httpGetGameAccKey(data.http_session.acc);
        sign_md5 = MD5(data.body+acc_key).toStr();
        if (0 != data.http_session.sign.compare(sign_md5)) break;

        log_debug("request_id:%d,ip:%s,target:%s,uid:%u,tid:%lu,acc:%s,key:%s,sign:%s,sign_md5:%s,body:%s", 
            data.request_id, data.ip.c_str(), data.target.c_str(), 
            data.http_session.uid, data.http_session.tid, data.http_session.acc.c_str(), 
            acc_key.c_str(), data.http_session.sign.c_str(), sign_md5.c_str(),
            CTools::ExportString(data.body).c_str());

        return true;
    } while (false);

    log_error("request_id:%d,ip:%s,target:%s,uid:%u,tid:%lu,acc:%s,key:%s,sign:%s,sign_md5:%s,body:%s", 
        data.request_id, data.ip.c_str(), data.target.c_str(), 
        data.http_session.uid, data.http_session.tid, data.http_session.acc.c_str(), 
        acc_key.c_str(), data.http_session.sign.c_str(), sign_md5.c_str(),
        CTools::ExportString(data.body).c_str());
    return false;
}

inline void httpResponse(std::uint32_t request_id, std::uint64_t request_time, const HttpSessionData& http_session, std::string&& body)
{
    std::string acc_key = httpGetGameAccKey(http_session.acc);
    std::string sign_md5 = MD5(body+acc_key).toStr();

	std::uint64_t response_time = CTools::GetUnixTimeMs();
    std::map<std::string,std::string> heads;
    heads["Content-Type"] = "application/json";
    heads["uid"] = std::to_string(http_session.uid);
    heads["tid"] = std::to_string(http_session.tid);
    heads["acc"] = http_session.acc;
    heads["sign"] = sign_md5;
    
    std::int64_t cost = response_time - request_time;
    if (cost > 50000) {
        log_warning("request_id:%u,heads:%s,body:%s,request_time:%lu,response_time:%lu,us_cost:%lu", 
            request_id, CTools::ToStr(heads,"&","=").c_str(), 
            CTools::ExportString(body).c_str(), 
            request_time, response_time, cost);
    }
    Ctx.msg_router.httpServerBack(request_id, 200, heads, std::move(body));
}

inline void httpErrResponse(std::uint32_t request_id, std::uint64_t request_time, std::int32_t httpCode, const HttpSessionData& http_session, std::string&& body)
{
    std::string acc_key = httpGetGameAccKey(http_session.acc);
    std::string sign_md5 = MD5(body+acc_key).toStr();

	std::uint64_t response_time = CTools::GetUnixTimeMs();
    std::map<std::string,std::string> heads;
    heads["Content-Type"] = "application/json";
    heads["uid"] = std::to_string(http_session.uid);
    heads["tid"] = std::to_string(http_session.tid);
    heads["acc"] = http_session.acc;
    heads["sign"] = sign_md5;
    
    std::int64_t cost = response_time - request_time;
    if (cost > 50000) {
        log_warning("request_id:%u,heads:%s,body:%s,request_time:%lu,response_time:%lu,us_cost:%lu", 
            request_id, CTools::ToStr(heads,"&","=").c_str(), 
            CTools::ExportString(body).c_str(), 
            request_time, response_time, cost);
    }
    Ctx.msg_router.httpServerBack(request_id, httpCode, heads, std::move(body));
}

template<typename T, class=typename std::enable_if<std::is_base_of<google::protobuf::Message, T>::value>::type >
inline void ResponseHttp(std::uint32_t request_id, std::uint64_t request_time, const HttpSessionData& http_session, T* msg)
{
    std::string body;
    if (msg != nullptr)
    {
        msg->SerializeToString(&body);
        // if (msg->err() != 0)
        // {
        //     log_error("request_id:%u,request_time:%lu,body:%s", 
        //         request_id, request_time, msg->ShortDebugString().c_str());
        // }
    }
    httpResponse(request_id, request_time, http_session, std::move(body));
}





